use std::collections::HashMap;

use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::error::Error;

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum ProcessType {
    #[default]
    Command,
    Wasm,
    HttpProxy,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "CommandProcessOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct CommandProcessOptions {
    pub command: String,
    pub args: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WasmProcessOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WasmProcessOptions {
    pub path: String,
    pub args: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "HttpProxyOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct HttpProxyOptions {
    pub host: String,
    pub port: u32,
    pub local_port: u32,
    pub urls: Vec<String>,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum ProcessOptions {
    #[default]
    Empty,
    Command(CommandProcessOptions),
    Wasm(WasmProcessOptions),
    HttpProxy(HttpProxyOptions),
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ProcessBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct Process {
    pub id: u32,
    pub r#type: ProcessType,
    pub identifier: String,
    pub options: ProcessOptions,
}

#[async_trait::async_trait]
pub trait ProcessManager {
    async fn query(&self, identifier: &String) -> anyhow::Result<i32>;

    async fn start(&self, identifier: &String, options: &ProcessOptions) -> anyhow::Result<u32>;

    async fn stop(&self, identifier: &String) -> anyhow::Result<i32>;
}

#[async_trait::async_trait]
pub trait ProcessMonitor {
    async fn status(&self, identifier: &String) -> anyhow::Result<i32>;
}
